/* $Id:unit.cc $ */
/*
   Copyright (C) 2007 by Jurjen Stellingwerff <jurjen@stwerff.xs4all.nl>
   Part of the Moros Project http://moros.sourceforge.net/

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 3.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#define DEBUG_ROUTINE "unit"

#include <sstream>
#include <fstream>
#include "../general/util.h"
#include "../general/log.h"
#include "../general/channel.h"
#include "unit.h"
#include "item.h"
#include "background.h"
#include "culture.h"
#include "skill.h"
#include "stat.h"
#include "../general/general.h"

unit::unit() {
    name="";
    description="";
    size=0;
    specials=map<int,class action_level>();
    maxSpecials=0;
    weapons=map<string,class material>();
    background=map<string,class background_level>();
    culture=map<string,class culture_part>();
    skills=map<string,class skill_level>();
    stats=map<string,class stat_amount>();
}

// Field : name

const string unit::getName() const { return name; }
void unit::setName(const string v) { name=v; }

// Field : description

const string unit::getDescription() const { return description; }
void unit::setDescription(const string v) { description=v; }

// Field : size

const int unit::getSize() const { return size; }
void unit::setSize(const int v) { size=v; }

// Field : specials

class action_level& unit::getSpecials(const int v) { return specials[v]; }
map<int,class action_level>& unit::listSpecials() { return specials; }
void unit::setSpecials(class action_level &v) {
    if (v.getNr()==0) v.setNr(++maxSpecials);
    specials[v.getNr()]=v;
}
void unit::delSpecials(const int v) { specials.erase(v); }
const bool unit::isSpecials(const int v) const { return specials.count(v)>0; }

// Field : weapons

class material& unit::getWeapons(const string v) { return weapons[v]; }
list<class material>& unit::listWeapons() {
    static list<class material> res;
    res.clear();
    loopMap(weapons,v,class material) {
        res.push_back(*v);
    }
    res.sort();
    return res;
}
void unit::setWeapons(class material &v) {
    weapons[v.getItem().getName()]=v;
}
void unit::delWeapons(const string v) { weapons.erase(v); }
const bool unit::isWeapons(const string v) const { return weapons.count(v)>0; }

// Field : background

class background_level& unit::getBackground(const string v) { return background[v]; }
list<class background_level>& unit::listBackground() {
    static list<class background_level> res;
    res.clear();
    loopMap(background,v,class background_level) {
        res.push_back(*v);
    }
    res.sort();
    return res;
}
void unit::setBackground(class background_level &v) {
    background[v.getBackground().getName()]=v;
}
void unit::delBackground(const string v) { background.erase(v); }
const bool unit::isBackground(const string v) const { return background.count(v)>0; }

// Field : culture

class culture_part& unit::getCulture(const string v) { return culture[v]; }
map<string,class culture_part>& unit::listCulture() { return culture; }
void unit::setCulture(class culture_part &v) {
    culture[v.getCulture().getName()]=v;
}
void unit::delCulture(const string v) { culture.erase(v); }
const bool unit::isCulture(const string v) const { return culture.count(v)>0; }

// Field : skills

class skill_level& unit::getSkills(const string v) { return skills[v]; }
map<string,class skill_level>& unit::listSkills() { return skills; }
void unit::setSkills(class skill_level &v) {
    skills[v.getSkill().getName()]=v;
}
void unit::delSkills(const string v) { skills.erase(v); }
const bool unit::isSkills(const string v) const { return skills.count(v)>0; }

// Field : stats

class stat_amount& unit::getStats(const string v) { return stats[v]; }
map<string,class stat_amount>& unit::listStats() { return stats; }
void unit::setStats(class stat_amount &v) {
    stats[v.getStat().getName()]=v;
}
void unit::delStats(const string v) { stats.erase(v); }
const bool unit::isStats(const string v) const { return stats.count(v)>0; }

void unit::save(class channel &ch) {
    ch.write("unit", "");
    ch.write("n", getName());
    ch.write("d", getDescription());
    ch.write("s", getSize());
    loopUnitSpecials(this, s_specials) {
        s_specials->save(ch);
    }
    loopUnitWeapons(this, s_weapons) {
        s_weapons->save(ch);
    }
    loopUnitBackground(this, s_background) {
        s_background->save(ch);
    }
    loopUnitCulture(this, s_culture) {
        s_culture->save(ch);
    }
    loopUnitSkills(this, s_skills) {
        s_skills->save(ch);
    }
    loopUnitStats(this, s_stats) {
        s_stats->save(ch);
    }
}

void unit::load(class channel &ch) {
    if (ch.key=="n" || ch.key=="name") { setName(ch.value); ch.next(); }
    if (ch.key=="d" || ch.key=="description") { setDescription(ch.value); ch.next(); }
    if (ch.key=="s" || ch.key=="size") { setSize(atoi(ch.value.c_str())); ch.next(); }
    while (ch.key=="action_level" || ch.key=="specials") {
        ch.next();
        class action_level rec;
        rec.load(ch);
        setSpecials(rec);
    }
    while (ch.key=="material" || ch.key=="weapons") {
        ch.next();
        class material rec;
        rec.load(ch);
        setWeapons(rec);
    }
    while (ch.key=="background_level" || ch.key=="background") {
        ch.next();
        class background_level rec;
        rec.load(ch);
        setBackground(rec);
    }
    while (ch.key=="culture_part" || ch.key=="culture") {
        ch.next();
        class culture_part rec;
        rec.load(ch);
        setCulture(rec);
    }
    while (ch.key=="skill_level" || ch.key=="skills") {
        ch.next();
        class skill_level rec;
        rec.load(ch);
        setSkills(rec);
    }
    while (ch.key=="stat_amount" || ch.key=="stats") {
        ch.next();
        class stat_amount rec;
        rec.load(ch);
        setStats(rec);
    }
}

void unit::xml(ofstream &f, int l, int r) {
    f << ncpy(l, "  ") << "<unit name=\"" << xml_encode(getName()) <<
    "\" description=\"" << xml_encode(getDescription()) <<
    "\" size=\"" << getSize() <<
    "\">" << endl;
    if (r==0) {
        loopUnitSpecials(this, s_specials) {
            s_specials->xml(f,l+1);
        }
        loopUnitWeapons(this, s_weapons) {
            s_weapons->xml(f,l+1);
        }
        loopUnitBackground(this, s_background) {
            s_background->xml(f,l+1);
        }
        loopUnitCulture(this, s_culture) {
            s_culture->xml(f,l+1);
        }
        loopUnitSkills(this, s_skills) {
            s_skills->xml(f,l+1);
        }
        loopUnitStats(this, s_stats) {
            s_stats->xml(f,l+1);
        }
    }
    f << ncpy(l, "  ") << "</unit>" << endl;
}

// Repository

unitRepository unit_repo;

class unit& unitRepository::getUnit(const string v) { return units[v]; }
void unitRepository::setUnit(class unit& v) {
    if (v.getName()=="") throw unnamed();
    units[v.getName()]=v;
}
map<string,class unit>& unitRepository::listUnit() { return units; }
void unitRepository::delUnit(const string v) { units.erase(v); }
const bool unitRepository::isUnit(const string v) const { return units.count(v)>0; }
void unitRepository::save(class channel &ch) {
    loopUnits(rec) {
        rec->save(ch);
    }
}

bool unitRepository::load(class channel &ch) {
    if (ch.key=="unit") {
        ch.next();
        class unit rec;
        rec.load(ch);
        setUnit(rec);
        return true;
    }
    return false;
}
